//
//  NetSession.cpp
//  FreeNet
//
//  Created by cc on 12-7-5.
//  Copyright (c) 2012年 cc. All rights reserved.
//

#include "NetSession.h"

namespace FreeNet {

#if defined (__SERVER__)
    int createTCPServer(const char* ip, const int port, NET_CALLBACK cb)
    {
        int fd = ::socket(AF_INET, SOCK_STREAM, 0) ;
        if (-1 == fd)
        {
            showError(err_str[0]) ;
            return -1 ;
        }
        int flag ;

        sockaddr_in localAddr ;
        localAddr.sin_family = AF_INET ;
        localAddr.sin_addr.s_addr = inet_addr(ip) ;
        localAddr.sin_port = htons(port) ;

        if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)))
        {
            showError(err_str[1]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (-1 == ::bind(fd, (struct sockaddr*)&localAddr, sizeof(struct sockaddr)))
        {
            perror("12") ;
            showError(err_str[2]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (-1 == ::listen(fd, 5))
        {
            showError(err_str[4]) ;
            ::close(fd) ;
            return -1 ;
        }
        socklen_t len ;
        if (-1 == ::accept(fd, (struct sockaddr*)&localAddr, &len))
        {
            showError(err_str[5]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (0 != cb) { cb() ; }
        return fd ;
    }

    int destroyTCPServer(const int fd, NET_CALLBACK cb)
    {
        int res = ::close(fd) ;
        if (0 != cb) { cb() ; }
        return res ;
    }
    
#if defined (__LINUX__)
    int createEpollServer(const char* ip, const int port, const eNetMode mode, const int max, NET_CALLBACK cb)
    {
        int res = -1 ;
        int fd = ::socket(AF_INET, SOCK_STREAM, 0) ;
        if (-1 == fd)
        {
            showError(err_str[0]) ;
            return -1 ;
        }
        int flag ;

        sockaddr_in localAddr ;
        localAddr.sin_family = AF_INET ;
        localAddr.sin_addr.s_addr = inet_addr(ip) ;
        localAddr.sin_port = htons(port) ;
        
        if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)))
        {
            showError(err_str[1]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (-1 == ::bind(fd, (struct sockaddr*)&localAddr, sizeof(struct sockaddr)))
        {
            showError(err_str[2]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (-1 == ::listen(fd, 5))
        {
            showError(err_str[4]) ;
            ::close(fd) ;
            return -1 ;
        }

        struct rlimit rl ;
        rl.rlim_max = rl.rlim_cur = max ;
        assert(-1 != setrlimit(RLIMIT_NOFILE, &rl)) ;
        int epoll_fd = ::epoll_create(max) ;
        assert(-1 != epoll_fd) ;

        struct epoll_event  ev ;
        ev.events = EPOLLIN | EPOLLET ;
        ev.data.fd = fd ;
        int op = fcntl(epoll_fd, F_GETFD, 0) ;
        assert(-1 != op) ;
        assert(-1 != fcntl(epoll_fd, F_SETFL, op | O_NONBLOCK)) ;

        if (0 != cb) { cb() ; }
        return 0 ;
    }

    int destroyEpollServer(const int fd, NET_CALLBACK cb)
    {
        int res = -1 ;
        if (0 != cb) { cb() ; }
        return res ;
    }

#elif defined (__MACOSX__)
    int createPollServer(const char* ip, const int port, const eNetMode mode, const int max, NET_CALLBACK cb)
    {
        int res = -1 ;
        int fd = ::socket(AF_INET, SOCK_STREAM, 0) ;
        if (-1 == fd)
        {
            showError(err_str[0]) ;
            return -1 ;
        }
        int flag ;

        sockaddr_in localAddr ;
        localAddr.sin_family = AF_INET ;
        localAddr.sin_addr.s_addr = inet_addr(ip) ;
        localAddr.sin_port = htons(port) ;
        
        if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)))
        {
            showError(err_str[1]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (-1 == ::bind(fd, (struct sockaddr*)&localAddr, sizeof(struct sockaddr)))
        {
            showError(err_str[2]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (-1 == ::listen(fd, 5))
        {
            showError(err_str[4]) ;
            ::close(fd) ;
            return -1 ;
        }

        struct pollfd pfd ;
        pfd.fd = fd ;
        pfd.events = max ;
        res = ::poll(&pfd, 1, 0) ;

        if (0 != cb) { cb() ; }
        ::printf("create poll server: ip [%s], port [%d]\n", ip, port) ;
        return 0 ;
    }
    int destroyPollServer(const int fd, NET_CALLBACK cb)
    {
        int res = -1 ;
        if (0 != cb) { cb() ; }
        return res ;
    }
#endif

    int disconnectClient(int fd, NET_CALLBACK cb)
    {
        int res = ::close(fd) ;
        if (0 != cb) { cb() ; }
        return res ;
    }
#endif

    int connectServer(const char* ip, const int port, const eNetMode mode, NET_CALLBACK cb)
    {
        int fd = ::socket(AF_INET, SOCK_STREAM, mode) ;
        int flag ;

        sockaddr_in localAddr ;
        localAddr.sin_family = mode ;
        localAddr.sin_addr.s_addr = inet_addr(ip) ;
        localAddr.sin_len = htons(port) ;

        if (-1 == fd)
        {
            showError(err_str[0]) ;
            return -1 ;
        }
        if (-1 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)))
        {
            showError(err_str[1]) ;
            ::close(fd) ;
            return -1 ;
        }
        if (-1 == ::connect(fd, (struct sockaddr*)&localAddr, sizeof(struct sockaddr)))
        {
            showError(err_str[3]) ;
            ::close(fd) ;
            return -1 ;
        }
        
        if (0 != cb) { cb() ; }
        return fd ;
    }

    int disconnectServer(const int fd, NET_CALLBACK cb)
    {
        int res = ::close(fd) ;
        if (0 != cb) { cb() ; }
        return res ;
    }
    
    size_t sendMessage(const void* data, const int len, const int fd, NET_CALLBACK cb)
    {
        size_t res = ::send(fd, data, len, 0) ;
        if (0 != cb) { cb() ; }
        return res ;
    }

    size_t recvMessage(void* &data, size_t& len, const int fd, NET_CALLBACK cb)
    {
        size_t res = ::recv(fd, data, len, 0) ;
        if (0 != cb) { cb() ; }
        return res ;
    }

    size_t sendMessageTo(const char* ip, const int port, const void* data, const int len, NET_CALLBACK cb)
    {
        sockaddr_in addr ;
        addr.sin_family = AF_INET ;
        addr.sin_addr.s_addr = inet_addr(ip) ;
        addr.sin_port = htons(port) ;

        size_t res = ::sendto(0, data, len, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr)) ;
        if (0 != cb) { cb() ; }
        return res ;
    }
    
    size_t recvMessageFrom(const char* ip, const int port, void* &data, size_t& len, NET_CALLBACK cb)
    {
        sockaddr_in addr ;
        addr.sin_family = AF_INET ;
        addr.sin_addr.s_addr = inet_addr(ip) ;
        addr.sin_port = htons(port) ;

        socklen_t flag ;
        size_t res = ::recvfrom(0, data, len, 0, (struct sockaddr*)&addr, &flag) ;
        if (0 != cb) { cb() ; }
        return res ;
    }
    
#if defined (__USEP2P__)
    int requestHole(const char* ip, const int port, NET_CALLBACK cb)
    {
        return ((0 == cb) ? 0 : cb()) ;
    }
#endif
}












